package mine.code.question.动态规划;

import org.junit.Test;

/**
 * 给定一个由整数数组 A表示的环形数组 C，求 C的非空子数组的最大可能和。
 * <p>
 * 在此处，环形数组意味着数组的末端将会与开头相连呈环状。（形式上，当0 <= i < A.length时C[i] = A[i]，且当i >= 0时C[i+A.length] = C[i]）
 * <p>
 * 此外，子数组最多只能包含固定缓冲区 A中的每个元素一次。（形式上，对于子数组C[i], C[i+1], ..., C[j]，不存在i <= k1, k2 <= j其中k1 % A.length= k2 % A.length）
 * <p>
 * 示例 1：
 * <p>
 * 输入：[1,-2,3,-2]
 * 输出：3
 * 解释：从子数组 [3] 得到最大和 3
 * <p>
 * 示例 2：
 * <p>
 * 输入：[5,-3,5]
 * 输出：10
 * 解释：从子数组 [5,5] 得到最大和 5 + 5 = 10
 * <p>
 * 示例 3：
 * <p>
 * 输入：[3,-1,2,-1]
 * 输出：4
 * 解释：从子数组 [2,-1,3] 得到最大和 2 + (-1) + 3 = 4
 * <p>
 * 示例 4：
 * <p>
 * 输入：[3,-2,2,-3]
 * 输出：3
 * 解释：从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3
 * <p>
 * 示例 5：
 * <p>
 * 输入：[-2,-3,-1]
 * 输出：-1
 * 解释：从子数组 [-1] 得到最大和 -1
 *
 * @author caijinnan
 */
public class 环形子数组的最大和 {

    @Test
    public void run() {
        int[] nums = {-2, -3, -1};
        System.out.println(maxSubarraySumCircular(nums));
    }

    public int maxSubarraySumCircular(int[] nums) {
        int countSum = 0;
        for (int num : nums) {
            countSum += num;
        }
        //累加值
        int maxSum = nums[0];
        //记录正数开始后,每次相加后的最大值
        int maxResultNum = nums[0];

        for (int i = 1, length = nums.length; i < length; i++) {
            if (maxSum < 0) {
                maxSum = nums[i];
            } else {
                maxSum += nums[i];
            }
            maxResultNum = Math.max(maxResultNum, maxSum);
        }

        //累加值
        int minSum = nums[0];
        //记录正数开始后,每次相加后的最大值
        int minResultNum = nums[0];
        for (int i = 1, length = nums.length; i < length; i++) {
            if (minSum > 0) {
                minSum = nums[i];
            } else {
                minSum += nums[i];
            }
            minResultNum = Math.min(minResultNum, minSum);
        }
        int temp = maxSum;
        if (countSum != minResultNum) {
            temp = countSum - minResultNum;
        }
        return Math.max(maxResultNum, temp);
    }
}
